/*
 * ArchivoIndice.cpp
 *
 *  Created on: 04/06/2013
 *      Author: jonathan
 *
 *  La escritura es termino a termino mientras que la lectura se hace por cabeceras de bloque.
 *
 *
 */

#include "ArchivoIndice.h"
#include "../../commons/InfoRepositorioActual.h"
#include "../../commons/PathsStore.h"
#include "../estructuras/EntradaIndice.h"
#include "../../commons/ArchivoUtils.h"
ArchivoIndice::ArchivoIndice(fstream::openmode mode) {
	this->tamanioBloque = InfoRepositorioActual::Instance()->getTamanioBloqueFC();
	PathsStore ps;
	this->bs = new BitStream(ps.getPathIndice(), mode);
	this->archFC = new ArchivoFrontCoding(mode);
}
ArchivoIndice::ArchivoIndice(FileName archIndice, FileName archFrontC, FileName archPtros, fstream::openmode mode) {
	this->bs = new BitStream(archIndice, mode);
	this->archFC = new ArchivoFrontCoding(archFrontC, archPtros, InfoRepositorioActual::Instance()->getTamanioBloqueFC(), mode);
	this->tamanioBloque = InfoRepositorioActual::Instance()->getTamanioBloqueFC();
}

ArchivoIndice::ArchivoIndice(FileName salida,FileName nombre, fstream::openmode mode) {
    string tabla= salida;
    string lexico= salida;
    string punteros= salida;
    tabla.append("/tabla.");
    tabla.append(nombre);
    lexico.append("/lexico.");
    lexico.append(nombre);
    punteros.append("/punteros.");
    punteros.append(nombre);
	this->bs = new BitStream(tabla.c_str(), mode);


	this->archFC = new ArchivoFrontCoding(lexico.c_str(),punteros.c_str(), InfoRepositorioActual::Instance()->getTamanioBloqueFC(), mode);
	this->tamanioBloque = InfoRepositorioActual::Instance()->getTamanioBloqueFC();
}

void ArchivoIndice::escribir(Termino& termino) {
	//escribo el contenido del termino.
	EntradaIndice * entrada = this->archFC->escribir(termino);
	//escribo la entrada del indice.
	bs->put(entrada->getCharsIguales());
	bs->put(entrada->getCharsDistintos());
	if (entrada->getPrincipal()) {
		escribirBinario(this->bs, entrada->getPtroLexico(), TAMANIO_OFFSET_LEXICO_BITS);
	}
	delete entrada;
}

ArchivoIndice::~ArchivoIndice() {
	delete this->bs;
	delete this->archFC;
}

void ArchivoIndice::close() {
	this->bs->close();
	this->archFC->close();
}

//El n arranca desde cero.
EnteroLargo ArchivoIndice::calcularOffset(int n) {
	EnteroLargo tamanio_bloque = InfoRepositorioActual::Instance()->getTamanioBloqueFC();
	//Multiplico el tamanio de un bloque mas el puntero a lexico que tiene y lo multiplico por la cantidad de bloques antes de n.
	return (tamanio_bloque*TAMANIO_REGISTRO + TAMANIO_OFFSET_LEXICO) * n;
}

//lee una cabecera de un bloque de entradas al indice ppal. n es el nro de bloque.
Cabecera ArchivoIndice::leerCabeceraBloque(int n) {
	EntradaIndice entrada = this->leerEntradaCabecera(n);
	Cabecera cabecera(n, entrada.getPtroLexico());
	cabecera.setTermino(this->archFC->leerCabecera(entrada));
	return cabecera;
}

EntradaIndice ArchivoIndice::leerEntradaCabecera(int n) {
	bs->seekg(this->calcularOffset(n));
	EntradaIndice entrada = this->leerEntradaSimple();
	entrada.setPrincipal(true);
	entrada.setPtroLexico(leerBinario(this->bs, TAMANIO_OFFSET_LEXICO_BITS));
	return entrada;
}

EntradaIndice ArchivoIndice::leerEntradaSimple(){
	EntradaIndice entrada;
	entrada.setCharsIguales(bs->get());
	entrada.setCharsDistintos(bs->get());
	entrada.setPrincipal(false);

	return entrada;
}

map<string, Termino*> * ArchivoIndice::leerTerminosBloque(Cabecera cabecera) {
	map<string, Termino*> *mapa = 0;
    EnteroLargo tamanioBloqueFC = InfoRepositorioActual::Instance()->getTamanioBloqueFC();
    //TODO REVISAR QUE LA CANTIDAD DE BLOQUES DEBE ESTAR CARGADA. y debo averiguar si el ultimo termino esta completo.
    //SI ES EL ULTIMO BLOQUE TENGO QUE LEER HASTA EL FINAL. sino leo la cantidad de terminos por bloque.

    //Esto es mas optimo q ir leyendo de a uno y pedir de a uno en el de front coding.
    list<EntradaIndice> entradas;

    //esto lee el primer elemento del bloque.
    entradas.push_back(this->leerEntradaCabecera(cabecera.getNro()));
    //ahora leo todos las entradas que siguen...

    EnteroLargo j;
    EnteroLargo ultima = (InfoRepositorioActual::Instance()->getCantidadBloquesFC()-1);
    if (cabecera.getNro() == ultima)
        j = InfoRepositorioActual::Instance()->getCantidadUltimoBloque();
    else
        j = tamanioBloqueFC;


    for(EnteroLargo i = 1; i<j ;i++){
    	entradas.push_back(this->leerEntradaSimple());
    }

    mapa = this->archFC->leerBloque(entradas);

	return mapa;
}
